/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.fd.manager.impl;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.xy.biz.base.client.DictClient;
import com.xy.biz.base.domain.constant.DictCodeConstant;
import com.xy.biz.base.domain.req.ListDictItemRequest;
import com.xy.biz.base.domain.resp.ListDictItemResponse;
import com.xy.biz.fd.dao.FolderDao;
import com.xy.biz.fd.dao.RepositoryDao;
import com.xy.biz.fd.domain.bo.FolderBO;
import com.xy.biz.fd.domain.bo.RepositoryBO;
import com.xy.biz.fd.domain.enums.DocumentDefaultRepositoryEnum;
import com.xy.biz.fd.domain.po.DocumentPO;
import com.xy.biz.fd.domain.po.FolderPO;
import com.xy.biz.fd.domain.req.folder.ListFolderRequest;
import com.xy.biz.fd.domain.resp.GetDocumentResponse;
import com.xy.biz.fd.manager.FolderManager;
import com.xy.biz.fd.manager.RepositoryManager;
import com.xy.biz.uc.client.UserGroupClient;
import com.xy.biz.uc.domain.dto.UserGroupDTO;
import com.xy.biz.uc.domain.req.ListUserGroupRequest;
import com.xy.lang.domain.Result;
import com.xy.lang.util.ResultUtils;
import com.xy.tool.context.UserContextHolder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xy.biz.fd.domain.bo.DocumentBO;
import com.xy.biz.fd.domain.query.DocumentQuery;
import com.xy.biz.fd.domain.converter.DocumentConverter;
import com.xy.biz.fd.manager.DocumentManager;
import com.xy.biz.fd.dao.DocumentDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 *
 *
 * @author wwj
 * @date 2021-2-1
 */
@Service
public class DocumentManagerImpl implements DocumentManager {

    @Autowired
    private DictClient dictClient;
    @Autowired
    private DocumentDao documentDao;
    @Autowired
    private FolderManager folderManager;
    @Autowired
    private RepositoryManager repositoryManager;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public GetDocumentResponse saveDocument(DocumentBO documentBO) {
        List<DocumentBO> documentBOList = new ArrayList<>();
        documentBOList.add(documentBO);
        buildDocumentFolderInfo(documentBOList);
        DocumentPO documentPO = DocumentConverter.toPO(documentBO);
        int row = documentDao.saveDocument(documentPO);
        if (row == 0) {
            return null;
        }
        GetDocumentResponse getDocumentResponse = DocumentConverter.toResponse(documentPO);
        return getDocumentResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<GetDocumentResponse> saveAllDocument(Collection<DocumentBO> collection) {
        buildDocumentFolderInfo(new ArrayList<>(collection));
        List<DocumentPO> documentPOS = DocumentConverter.toPO(collection);
        int row = documentDao.saveAllDocument(documentPOS);
        if (row == 0) {
            return null;
        }
        List<GetDocumentResponse> getDocumentResponse = DocumentConverter.toResponse(DocumentConverter.fromPO(documentPOS));
        return getDocumentResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDocument(DocumentBO documentBO) {
        List<DocumentBO> documentBOList = new ArrayList<>();
        documentBOList.add(documentBO);
        buildDocumentFolderInfo(documentBOList);
        return documentDao.updateDocument(DocumentConverter.toPO(documentBO));
    }

    /**
     * 批量更新
     *
     * @param documentBOS
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateDocumentAll(Collection<DocumentBO> documentBOS) {
        buildDocumentFolderInfo(new ArrayList<>(documentBOS));
        return documentDao.updateDocumentAll(DocumentConverter.toPO(documentBOS));
    }

    /**
     * 批量更新
     *
     * @param query
     */
    @Override
    public int updateDocumentByIds(DocumentQuery query) {
        return documentDao.updateDocumentByIds(query);
    }

    @Override
    public int updateDocumentPermission(DocumentBO documentBO) {
        return documentDao.updateDocumentPermission(DocumentConverter.toPO(documentBO));
    }

    @Override
    public int deleteDocument(Long documentId) {
        return documentDao.deleteDocument(documentId);
    }

    /**
     * 删除
     *
     * @param documentIds
     */
    @Override
    public int deleteDocuments(Collection<Long> documentIds) {
        return documentDao.deleteDocuments(documentIds);
    }

    @Override
    public DocumentBO getDocumentPath(String path) {
        return DocumentConverter.fromPO(documentDao.getDocumentPath(path));
    }

    @Override
    public DocumentBO getDocument(Long documentId) {
        return DocumentConverter.fromPO(documentDao.getDocument(documentId));
    }

    /**
     * 查找一个流程最新版本
     *
     * @param documentQuery
     * @return
     */
    @Override
    public DocumentBO getLatestVersion(DocumentQuery documentQuery) {
        return DocumentConverter.fromPO(documentDao.getLatestVersion(documentQuery));
    }

    @Override
    public List<DocumentBO> listDocumentById(Collection<Long> collection) {
        if (CollectionUtils.isEmpty(collection)) {
            return null;
        }
        return DocumentConverter.fromPO(documentDao.listDocumentById(collection));
    }

    @Override
    public List<DocumentBO> listDocument(DocumentQuery query) {
        return DocumentConverter.fromPO(documentDao.listDocument(query));
    }

    @Override
    public int countDocument(DocumentQuery query) {
        return documentDao.countDocument(query);
    }

    @Override
    public DocumentPO updateDocumentSizeByPath(DocumentBO documentBO) {
        DocumentPO documentPO = DocumentConverter.toPO(documentBO);
        documentDao.updateDocumentSizeByPath(documentPO);
        return documentPO;
    }

    @Override
    public List<DocumentBO> listDocumentByName(DocumentBO documentBO) {
        DocumentPO documentPO = DocumentConverter.toPO(documentBO);
        return DocumentConverter.fromPO(documentDao.listDocumentByName(documentPO));
    }

    /**
     * @author Greekn Zhang
     * @date 2021/12/7 14:08
     * @param documentBOList
     * @description 流程文件使用特殊库
     */
    private void buildDocumentFolderInfo(List<DocumentBO> documentBOList) {
        DocumentDefaultRepositoryEnum[] values = DocumentDefaultRepositoryEnum.values();
        documentBOList.removeIf(e -> {
            if (Objects.isNull(e.getRepositoryId())) {
                return true;
            }
            return Arrays.stream(values).noneMatch(element -> e.getRepositoryId().equals(element.getCode()));
        });
        if (CollectionUtils.isEmpty(documentBOList)) {
            return;
        }
        Result<List<ListDictItemResponse>> result =
                dictClient.listDictItem(ListDictItemRequest.builder().dictGroupCode(DictCodeConstant.DOCUMENT_CATEGORY).build());
        if (!result.wasSuccess()) {
            return;
        }
        Map<String, String> dictMap =
                result.getData().stream().collect(Collectors.toMap(ListDictItemResponse::getDictCode, ListDictItemResponse::getDictValue));
        Map<Long, RepositoryBO> repositoryBOMap = new HashMap<>();
        Map<FolderWrapper, FolderBO> folderBOMap = new HashMap<>();
        documentBOList.forEach(e -> {
            Long repositoryId = e.getRepositoryId();
            RepositoryBO repository =
                    repositoryBOMap.computeIfAbsent(repositoryId, (k) -> repositoryManager.getRepository(repositoryId));
            FolderWrapper wrapper = new FolderWrapper(repositoryId, 0L, dictMap.get(String.valueOf(e.getLevel())));
            FolderBO parentFolder = folderBOMap.computeIfAbsent(wrapper,
                    (k) -> getFolder(null, repositoryId, repository.getRepositoryName(), dictMap.get(String.valueOf(e.getLevel()))));
            e.setFolderId(parentFolder.getFolderId());
        });
    }

    private FolderBO getFolder(FolderBO folderBO, Long repositoryId, String repositoryName, String folderName) {
        if (Objects.isNull(folderName)) {
            folderName = "其他";
        }
        FolderBO folder =
                folderManager.getFolderByNameAndRepository(ListFolderRequest.builder().repositoryId(repositoryId).parentFolderId(Objects.isNull(folderBO) ? null : folderBO.getFolderId()).folderName(folderName).build());
        if (Objects.isNull(folder)) {
            LocalDateTime now = LocalDateTime.now();
            folder = folderManager.saveFolder(FolderBO.builder()
                    .folderName(folderName)
                    .parentFolderId(Objects.isNull(folderBO) ? 0L : folderBO.getFolderId())
                    .repositoryId(repositoryId)
                    .sequence(0)
                    .permission(0)
                    .location(repositoryName + "://" + (Objects.isNull(folderBO) ? "" : folderBO.getFolderName()))
                    .folderSize(0L)
                    .tenantId(UserContextHolder.getTenantId())
                    .createUserId(UserContextHolder.getUserId())
                    .accessTime(now)
                    .updateTime(now)
                    .createTime(now)
                    .build());
        }
        return folder;
    }

    @Data
    @EqualsAndHashCode
    @AllArgsConstructor
    static class FolderWrapper {
        private Long repositoryId;
        private Long parentFolderId;
        private String folderName;
    }

}
